﻿// Copyright (c) 2012 Mokah Nnamezie & Andrew Cooper
// Neo4Net graph database - http://neo4net.codeplex.com
//
// This file is part of Neo4Net - a .Net port of the Neo4j graph database
//
// Neo4Net is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

namespace Neo4Net.Kernel
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using Neo4Net.GraphDb;
    using Neo4Net.Helpers.Collection;

    public partial class GuardPerformanceImpact
    {
        private static readonly int runs = 10;
        private static readonly int perTx = 10000;
        private static readonly int tx = 100;

        public static void Main(string[] args)
        {
            Test(Type.Enabled);
        }

        private static void Test(Type type)
        {
            switch (type)
            {
                case Type.Without:
                    for (int i = 0; i < runs; i++)
                    {
                        Console.Error.WriteLine(WithoutGuard());
                    }
                    break;

                case Type.Enabled:
                    for (int i = 0; i < runs; i++)
                    {
                        Console.Error.WriteLine(GuardEnabled());
                    }
                    break;

                case Type.ActiveOpscount:
                    for (int i = 0; i < runs; i++)
                    {
                        Console.Error.WriteLine(GuardEnabledAndActiveOpsCount());
                    }
                    break;

                case Type.ActiveTimeout:
                    for (int i = 0; i < runs; i++)
                    {
                        Console.Error.WriteLine(GuardEnabledAndActiveTimeout());
                    }
                    break;
            }
        }

        private static long WithoutGuard()
        {
            AbstractGraphDatabase db = Prepare(false);
            try
            {
                var sw = Stopwatch.StartNew();

                CreateData(db);

                return sw.ElapsedMilliseconds;
            }
            finally
            {
                Cleanup(db);
            }
        }

        private static AbstractGraphDatabase Prepare(bool insertGuard)
        {
            string tmpFileName = Path.GetTempFileName();
            File.Delete(tmpFileName);

            return new EmbeddedGraphDatabase(tmpFileName, DictionaryUtil.StringMap("enable_execution_guard", insertGuard.ToString()));
        }

        private static void CreateData(AbstractGraphDatabase db)
        {
            for (int j = 0; j < tx; j++)
            {
                ITransaction transaction = db.BeginTx();
                for (int i = 0; i < perTx; i++)
                {
                    db.CreateNode();
                }
                transaction.Success();
                transaction.Finish();
            }
        }

        private static void Cleanup(AbstractGraphDatabase db)
        {
            db.Shutdown();
            DeleteFiles(new DirectoryInfo(db.StoreDir));
        }

        private static void DeleteFiles(FileSystemInfo fileSystemObject)
        {
            var directory = fileSystemObject as DirectoryInfo;
            if (directory != null)
            {
                FileSystemInfo[] files = directory.GetFileSystemInfos();
                if (files != null)
                {
                    foreach (FileInfo file in files)
                    {
                        DeleteFiles(file);
                    }
                }
            }
            fileSystemObject.Delete();
        }

        private static long GuardEnabled()
        {
            AbstractGraphDatabase db = Prepare(true);
            try
            {
                var sw = Stopwatch.StartNew();

                CreateData(db);
                return sw.ElapsedMilliseconds;
            }
            finally
            {
                Cleanup(db);
            }
        }

        private static long GuardEnabledAndActiveOpsCount()
        {
            AbstractGraphDatabase db = Prepare(true);
            try
            {
                var sw = Stopwatch.StartNew();

                db.Guard.StartOperationsCount(Int32.MaxValue);

                CreateData(db);

                return sw.ElapsedMilliseconds;
            }
            finally
            {
                Cleanup(db);
            }
        }

        private static long GuardEnabledAndActiveTimeout()
        {
            AbstractGraphDatabase db = Prepare(true);
            try
            {
                var sw = Stopwatch.StartNew();

                db.Guard.StartTimeout(Int32.MaxValue);

                CreateData(db);
                return sw.ElapsedMilliseconds;
            }
            finally
            {
                Cleanup(db);
            }
        }
    }
}
